package com.bjpowernode.filter;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.bjpowernode.constant.Constant;
import com.bjpowernode.entity.TUser;
import com.bjpowernode.result.R;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class TokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        //先判断是不是登录接口，如果是登录接口，不需要验证token
        String requestUri = request.getRequestURI();
        if(requestUri.equals("/login")){
            filterChain.doFilter(request,response);
            return;
        }
        //从请求头中获取token
        String token = request.getHeader("token");
        if(!StringUtils.hasText(token)){
            R result = R.builder().code(901).msg("请求token为空").build();
            response.getWriter().write(JSONUtil.toJsonStr(result));
            return;
        }
        //验证token
        boolean verify = false;
        //如果验证抛出异常则说明token被篡改过，不合法
        try{
            verify = JWTUtil.verify(token, Constant.SECRET.getBytes());
        }catch (Exception e){
            e.printStackTrace();
        }
        if(!verify){
            R result = R.builder().code(902).msg("token不合法").build();
            response.getWriter().write(JSONUtil.toJsonStr(result));
            return;
        }
        //解析token
        JWT jwt = JWTUtil.parseToken(token);
        JSONObject payloads = jwt.getPayloads();
        //存的时候，token的负载存的是user的json
        String userJson = payloads.get("user", String.class);
        TUser user = JSONUtil.toBean(userJson,TUser.class);
        //然后获取用户id
        Integer id = user.getId();
        //从redis中获取对应token
        String redisToken = (String) redisTemplate.opsForHash().get(Constant.REDIS_TOKEN_KEY, id.toString());
        //比较传过来的token和redis中的token是否相同
        if(!token.equals(redisToken)){
            R result = R.builder().code(903).msg("请求token错误").build();
            response.getWriter().write(JSONUtil.toJsonStr(result));
            return;
        }
        //token验证通过后，要在spring security上下文中放置一个认证对象，因为当前这个filter执行
        //完之后，可能还会执行后续spring security框架自己的filter，如果不在上下文中放置一个认证
        //对象，security框架就不知道用户登录了，就会把当前请求直接重定向到登录页。
        //创建一个认证对象，该对象是Authentication的一个实现类,第一个参数是用户对象，
        //第二个参数是用户的密码，这里传null，第三个参数是用户的权限集合
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(user,null,
                        user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //然后放行
        filterChain.doFilter(request,response);
    }
}
